We consider control transfer to be the fundamental result of comparison, rather than anything such as a condition code. Although most compilers with whizzy register allocation seem to explicitly allocate and manipulate the condition codes, it seems that any benefit is small in our case. This is partly because our VOPs are at a somewhat higher level, making it difficult to tell which VOPs do and don't trash the the CC. Explicitly incorporating condition codes in our VM also introduces another architecture dependency.
At the IR2 level, we have a class of IF-XXX VOPs which transfer control to one of two places on the basis of some test on the operands. When generating code for a predicate, we peek at the destination IF node to find where to transfer control to.
The exact representation of type tests in IR2 will be fairly implementation dependent, since it will depend on the specific type system for the given implementation. For example, if an implementation can test some types with a simple tag check, but other types require reading a field from the object in addition, then the two different kinds of checks should be distinct at the VOP level, since this will allow the VOP cost and storage information to be more accurate. Generation of type tests should be factored out of code which would otherwise be more portable. Probably the IR2 translator for TYPEP and the type check generation code are the only places that should know about how type tests are represented in IR2.
if-type (object) if-type-range If-Type Tests whether Object has the type code that is passed in the codegen info. If-Type-Range tests for a range of type codes.
small, fast if-vector-type (object) Test that Object is either of the specified type code, or is a 1d array header with data having the specified type code.
if-vector-subtype (object) Test the subtype field of a vector-like object. It is assumed that the object has already been determined to be vector-like.
if-fixnump (object) if-short-float-p if-characterp The rationale behind having these as separate VOPs is that they are likely to be immediate types, and thus may have bizzare type schemes.
if-consp (object) if-listp We have distinct operations for these predicates since one or the other isn't a simple tag test, but we don't know which one.
if-rationalp (object) if-floatp if-integerp if-numberp if-vectorp if-functionp The rationale behind having these operations is that they may take a lot of code, so it is reasonable to put them out of line.